package com.pig4cloud.pig.ads.service.impl;

import com.alibaba.fastjson.JSON;
import com.baidu.dev2.api.sdk.common.ApiRequestHeader;
import com.baidu.dev2.api.sdk.invoke.ApiException;
import com.baidu.dev2.api.sdk.ocpctransfeed.api.OcpcTransFeedService;
import com.baidu.dev2.api.sdk.ocpctransfeed.model.*;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.dy.sdk.client.DyGdtClient;
import com.google.api.client.util.Lists;
import com.pig4cloud.pig.ads.gdt.service.GdtAccesstokenService;
import com.pig4cloud.pig.ads.gdt.service.GdtChannelPackageService;
import com.pig4cloud.pig.ads.pig.mapper.AdConvertMapper;
import com.pig4cloud.pig.ads.service.AdAccesstokenService;
import com.pig4cloud.pig.ads.service.AdConvertService;
import com.pig4cloud.pig.ads.service.AdOauthSettingService;
import com.pig4cloud.pig.api.dto.AdConvertRes;
import com.pig4cloud.pig.api.entity.AdAccountToken;
import com.pig4cloud.pig.api.entity.AdConvert;
import com.pig4cloud.pig.api.entity.AdOauthSetting;
import com.pig4cloud.pig.api.entity.GdtChannelPackage;
import com.pig4cloud.pig.api.enums.GdtDeepWorthOptimizationGoalEnum;
import com.pig4cloud.pig.api.enums.GdtOptimizationGoalEnum;
import com.pig4cloud.pig.api.vo.AdConvertReq;
import com.pig4cloud.pig.common.core.constant.enums.PlatformTypeEnum;
import com.pig4cloud.pig.common.core.util.R;
import com.tencent.ads.model.*;
import lombok.RequiredArgsConstructor;
import lombok.extern.log4j.Log4j2;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.*;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * 广告转化表
 * @author  chenxiang
 * @version  2022-05-23 10:35:26
 * table: ad_convert
 */
@Log4j2
@Service("adConvertService")
@RequiredArgsConstructor
public class AdConvertServiceImpl extends ServiceImpl<AdConvertMapper, AdConvert> implements AdConvertService {

	private final DyGdtClient client = new DyGdtClient();
	@Resource
	private GdtAccesstokenService gdtAccesstokenService;

	private final AdAccesstokenService adAccesstokenService;

	private final GdtChannelPackageService gdtChannelPackageService;

	private final AdOauthSettingService adOauthSettingService;

	@Override
	public R getList(AdConvert record){
		try {
			List<AdConvert> adConvertList = this.list(Wrappers.<AdConvert>lambdaQuery()
					.eq(AdConvert::getAdvertiserId,record.getAdvertiserId())
					.eq(Objects.nonNull(record.getAppId()),AdConvert::getPromotedObjectId,record.getAppId())
					.like(StringUtils.isNotBlank(record.getConvertName()),AdConvert::getConvertName,record.getConvertName())
					.eq(AdConvert::getMediaCode, PlatformTypeEnum.GDT.getValue())
					.eq(AdConvert::getStatus,AdConvert.Status.ACCESS_STATUS_COMPLETED)
					.eq(AdConvert::getDeleted,0));

			List<AdConvertRes> result = new ArrayList<>();
			if (CollectionUtils.isNotEmpty(adConvertList)){
				for (AdConvert convert : adConvertList) {
					AdConvertRes convertRes = new AdConvertRes(convert.getConvertId(),convert.getConvertName());
					convertRes.setConvertTargetValue(convert.getConvertTarget());
					convertRes.setConvertTargetName(GdtOptimizationGoalEnum.valueByType(convert.getConvertTarget()));
					if (StringUtils.isNotBlank(convert.getDeepConversionType())) {
						convertRes.setDeepConversionValue(convert.getDeepConversionType());
						//创建转化时，深度优化行为目标、优化ROI、强化ROI只能选择一个且DB使用一个字段存储
						String deepName = GdtOptimizationGoalEnum.valueByType(convert.getDeepConversionType());
						convertRes.setDeepConversionName(StringUtils.isBlank(deepName)? GdtDeepWorthOptimizationGoalEnum.getNameByType(convert.getDeepConversionType()):deepName);
					}
					result.add(convertRes);
				}
			}
			return R.ok(result);
		} catch (Exception e) {
			e.printStackTrace();
			return R.failed(e.getMessage());
		}
	}


	/**
	 * 新增转化归因
	 * @param record
	 * @return
	 */
	@Override
	public R createGdtConversions(AdConvert record){
		GdtChannelPackage channelPackage = gdtChannelPackageService.getOne(Wrappers.<GdtChannelPackage>lambdaQuery()
				.eq(GdtChannelPackage::getUnionAppId, record.getAppId())
				.eq(GdtChannelPackage::getAppChl, record.getPackageName())
				.last("LIMIT 1"));
		if (Objects.isNull(channelPackage)){
			return R.failed("未获取到渠道包信息");
		}
		record.setAppName(channelPackage.getPackageName());
		record.setPromotedObjectId(channelPackage.getUnionAppId());
		record.setAppAndroidChannelPackageId(channelPackage.getChannelPackageId());

		// 新增转化归因 - 广点通
		R result = this.conversionsAdd(record);
		if (0 == result.getCode()){
			ConversionsAddResponseData data = (ConversionsAddResponseData) result.getData();
			Long convertId = data.getConversionId();
			record.setConvertId(String.valueOf(convertId));
			record.setSoucreStatus(1);
			// 新增
			boolean flag = this.save(record);
			if (flag){
				// 创建成功， 异步线程拉取一次转化归因
				ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(1);
				executor.schedule(new Runnable() {
					@Override
					public void run() {
						synGdtConversions(record);
					}
				}, 5, TimeUnit.SECONDS);
				executor.shutdown();

				return R.ok(record);
			}
			return R.failed();
		}else{
			return result;
		}
	}
	/**
	 * 新增转化归因 - 广点通
	 * @param record
	 * @return
	 */
	public R conversionsAdd(AdConvert record){
//		List<String> siteSet = Lists.newArrayList("SITE_SET_MOBILE_UNION","SITE_SET_TENCENT_NEWS");
		ConversionsAddRequest data = new ConversionsAddRequest();
		data.setAccountId(Long.valueOf(record.getAdvertiserId()));
		data.setConversionName(record.getConvertName());
		data.setAccessType(AccessType.SDK);
		data.setConversionScene(ConversionScene.fromValue(record.getConversionScene()));
		//推广目标ID,即应用ID 字段必填，文档不对
		data.setPromotedObjectId(String.valueOf(record.getAppId()));
		//渠道包ID--传入此字段创建成功但媒体后台没有，其实是失败的
		// TODO 创建转化是 ad_convert.chl 要存储分包编码和冗余渠道包ID,便于创建广告使用渠道包ID
//        data.setAppAndroidChannelPackageId("0;2697648");
		data.setClaimType(ClaimType.fromValue(record.getClaimType()));
		data.setFeedbackUrl(record.getActionTrackUrl());
		data.setSelfAttributed(Boolean.FALSE);
		data.setOptimizationGoal(IntOptimizationGoal.fromValue(record.getConvertTarget()));
		data.setDeepBehaviorOptimizationGoal(IntOptimizationGoal.fromValue(record.getDeepConversionType()));
//        data.setDeepWorthAdvancedGoal(ConversionOptimizationGoal._1DAY_MONETIZATION_ROAS);
		try {
			Map<String, String> tokenMap = gdtAccesstokenService.fetchAccesstoken(record.getAdvertiserId());
			log.info(">>>广点通新增转化归因param：{}", JSON.toJSONString(data));
			ConversionsAddResponseData response = client.getTencentAds(tokenMap.get("access_token")).conversions().conversionsAdd(data);
			log.info(">>>广点通新增转化归因result：{}", JSON.toJSONString(response));
			return R.ok(response);
		} catch (Exception e) {
			log.error(">>>广点通新增转化归因异常：{}", e);
			return R.failed(e.getMessage());
		}
	}

	/**
	 * 创建成功， 异步线程拉取一次转化归因
	 * @param adConvert
	 */
	public void synGdtConversions(AdConvert adConvert){
		try {
			Map<String, String> tokenMap = gdtAccesstokenService.fetchAccesstoken(adConvert.getAdvertiserId());
			List<String> fields = Arrays.asList("conversion_id", "conversion_name", "access_type", "claim_type", "feedback_url", "optimization_goal", "deep_behavior_optimization_goal", "deep_worth_optimization_goal", "is_deleted", "access_status", "app_android_channel_package_id", "promoted_object_id");
			List<FilteringStruct> filtering = Lists.newArrayList();
			FilteringStruct filteringStruct = new FilteringStruct();
			filteringStruct.field("conversion_id");
			filteringStruct.setOperator("EQUALS");
			List values = Lists.newArrayList();
			values.add(adConvert.getConvertId());
			filteringStruct.setValues(values);
			filtering.add(filteringStruct);
			// 获取转化归因
			ConversionsGetResponseData response = client.getTencentAds(tokenMap.get("access_token")).conversions().conversionsGet(Long.valueOf(adConvert.getAdvertiserId()), filtering,1L,10L,fields);
			if (CollectionUtils.isNotEmpty(response.getList())){
				for (ConversionsGetListStruct conversionsGetListStruct : response.getList()){
					AdConvert updateConvert = new AdConvert();
					updateConvert.setId(adConvert.getId());
					updateConvert.setStatus(conversionsGetListStruct.getAccessStatus().getValue());
					updateConvert.setUpdateTime(new Date());
					this.updateById(updateConvert);
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	/**
	 * 根据advertiser_monitor_info主键获取列表
	 * @param record
	 * @return
	 */
	public R getAdConvertListInner(AdConvertReq record){
		List<AdConvert> adConvertList = this.list(Wrappers.<AdConvert>lambdaQuery().in(AdConvert::getAdId, record.getAdIds()).eq(AdConvert::getDeleted,0));
		return R.ok(adConvertList);
	}

	/**
	 * 百度-新增转化
	 * @return
	 */
	@Override
	public R addOcpcTransFeed(AdConvertReq record){
		try {
			String advertiserId = record.getAdvertiserId();
			AdAccountToken adAccountToken = adAccesstokenService.getAdAccountToken(PlatformTypeEnum.BD.getValue(), advertiserId);
			if (Objects.isNull(adAccountToken)){
				return R.failed("未获取到广告账户Token信息");
			}
			AdOauthSetting adOauthSetting = adOauthSettingService.getOauthSetting(PlatformTypeEnum.BD.getValue());
			if (Objects.isNull(adAccountToken)){
				return R.failed("未获取到媒体配置信息");
			}
			OcpcTransFeedService feedService = new OcpcTransFeedService();
			AddOcpcTransFeedRequestWrapper wrapper = new AddOcpcTransFeedRequestWrapper();
			wrapper.setHeader(new ApiRequestHeader().accessToken(adAccountToken.getAccessToken()).userName(adAccountToken.getAdvertiserName()));
			AddOcpcTransFeedRequest body = new AddOcpcTransFeedRequest();
			List<OcpcTransApiType> ocpcTransApiTypeList = new ArrayList<>();
			OcpcTransApiType ocpcTransApiType = new OcpcTransApiType();
			// 1 - 应用API 	13 - 应用SDK
			ocpcTransApiType.setTransFrom(13);
			ocpcTransApiType.setTransName(record.getConvertName());
			ocpcTransApiType.setTransTypes(com.google.common.collect.Lists.newArrayList(Integer.valueOf(record.getConvertTarget())));
			ocpcTransApiType.setDeepTransTypes(StringUtils.isNotBlank(record.getDeepConversionType()) ? com.google.common.collect.Lists.newArrayList(Integer.valueOf(record.getDeepConversionType())) : com.google.common.collect.Lists.newArrayList());
			ocpcTransApiType.setMode(1);
			ocpcTransApiType.setDownloadUrl(record.getDownloadUrl());
			ocpcTransApiType.setMonitorUrl(record.getActionTrackUrl());
			ocpcTransApiType.setAppType(2);
			ocpcTransApiType.setApkName(record.getPackageName());
			ocpcTransApiType.setAppName(record.getAppName());
			ocpcTransApiType.setSdkAppId(Long.valueOf(record.getAppId()));
			ocpcTransApiType.setSdkSecretKey(adOauthSetting.getAppSecret());
			ocpcTransApiTypeList.add(ocpcTransApiType);
			body.setOcpcTransFeedTypes(ocpcTransApiTypeList);
			wrapper.body(body);
			log.info(">>>百度-新增转化param:{}", JSON.toJSONString(wrapper));
			AddOcpcTransFeedResponseWrapper response = feedService.addOcpcTransFeed(wrapper);
			log.info(">>>百度-新增转化result:{}", JSON.toJSONString(response));
			if (null != response && response.getHeader().getStatus().equals(0)){
				AddOcpcTransFeedResponseWrapperBody wrapperBody = response.getBody();
				List<OcpcTransApiType> transApiTypeList = wrapperBody.getData();
				if (CollectionUtils.isNotEmpty(transApiTypeList)){
					OcpcTransApiType transApiType = transApiTypeList.get(0);
					AdConvert adConvert = this.saveAdConvert(record, transApiType);
					return R.ok(adConvert);
				}
			}else{
				log.error(">>>百度-新增转化失败：{}", JSON.toJSONString(response));
				return R.failed(null, response.getHeader().getFailures().get(0).getMessage());
			}
		} catch (ApiException e) {
			log.error(">>>百度-新增转化异常：{}", e.getMessage());
		}
		return R.failed();
	}

	public AdConvert saveAdConvert(AdConvertReq record, OcpcTransApiType transApiType){
		AdConvert adConvert = new AdConvert()
				.setAdId(record.getAdId())
				.setPgameId(Long.valueOf(record.getPgameId()))
				.setGameId(Long.valueOf(record.getGameId()))
				.setChl(record.getChl())
				.setMediaCode(record.getMediaCode())
				.setAdvertiserId(record.getAdvertiserId())
				.setConvertId(String.valueOf(transApiType.getAppTransId()))
				.setConvertName(record.getConvertName())
				.setConvertTarget(JSON.toJSONString(com.google.common.collect.Lists.newArrayList(Integer.valueOf(record.getConvertTarget()))))
				.setDeepConversionType(JSON.toJSONString(com.google.common.collect.Lists.newArrayList(Integer.valueOf(record.getDeepConversionType()))))
				.setActionTrackUrl(record.getActionTrackUrl())
				.setAppId(Long.valueOf(record.getAppId()))
				.setAppName(record.getAppName())
				.setPackageName(record.getPackageName())
				.setStatus(String.valueOf(transApiType.getTransStatus()))
				.setSoucreStatus(1)
				.setCreateTime(new Date()).setUpdateTime(new Date())
				.setCreateId(record.getCreateId());
		this.save(adConvert);
		return adConvert;
	}

}


